package com.hclc.config.context;

import com.hclc.config.context.constants.GlobalNames;
import com.hclc.config.context.exception.AuthenticationException;
import com.hclc.config.util.AssertUtil;
import com.hclc.entity.model.contans.ApiConst;
import com.hclc.config.context.constants.Constants;
import com.hclc.util.json.JsonUtil;
import lombok.extern.slf4j.Slf4j;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;


/**
 * @ClassName AppContext
 * @Author: yurj
 * @Mail：1638234804@qq.com
 * @Date: Create in 15:49 2020-2-9
 * @version: 1.0
 */
@Slf4j
public final class AppContext {
    @SuppressWarnings("rawtypes")
    private static final ThreadLocal userCtx = new ThreadLocal();
    /**
     * 框架级缓存Map
     */
    private static final Map<String, Object> cacheMap = new ConcurrentHashMap<String, Object>();

    /**
     * spring bean缓存
     */
    private static final Map<String, Object> beanCacheMap = new ConcurrentHashMap<String, Object>();

    private AppContext() {

    }

    /**
     * 获取当前登录用户
     *
     * @param clazz
     * @return T
     * @author yurj
     * @mail 1638234804@qq.com
     * @version 1.0
     * @date 2020/7/5 13:42
     */

    public static <T> T getCurrentUser(Class<T> clazz) {
        CurrentThreadUser currentThreadUser = (CurrentThreadUser) getThreadContext(GlobalNames.SESSION_CONTEXT_USERINFO_KEY);
        AssertUtil.authNotNull(currentThreadUser, () -> "Current login user is null");
        return JsonUtil.toObject(JsonUtil.toJson(currentThreadUser.getUser()), clazz);

    }

    /**
     * 获取当前用户登录token
     *
     * @param
     * @return java.lang.String
     * @author yurj
     * @mail 1638234804@qq.com
     * @version 1.0
     * @date 2020/7/5 14:10
     */

    public static String getCurrentUserToken() {
        CurrentThreadUser currentThreadUser = (CurrentThreadUser) getThreadContext(GlobalNames.SESSION_CONTEXT_USERINFO_KEY);
        AssertUtil.authNotNull(currentThreadUser, () -> "Current login user is null");
        String token = currentThreadUser.getToken();
        if (Objects.isNull(token)) {
            token = (String) getThreadContext(GlobalNames.THREAD_CONTEXT_REQUEST_KEY);
        }
        return token;
    }

    /**
     * 获取当前登录用户id
     *
     * @param
     * @return java.lang.String
     * @author yurj
     * @version 1.0
     * @date 2020/10/17 9:48
     */
    public static String getCurrentUserId() {
        CurrentThreadUser currentThreadUser = (CurrentThreadUser) getThreadContext(GlobalNames.SESSION_CONTEXT_USERINFO_KEY);
        AssertUtil.authNotNull(currentThreadUser, () -> "Current login user is null");
        String userId = currentThreadUser.getUserId();
        if (Objects.isNull(userId)) {
            userId = (String) getThreadContext(GlobalNames.THREAD_CONTEXT_REQUEST_KEY);
        }
        return userId;
    }

    /**
     * 获取线程上下文参数
     *
     * @param ctxKey
     * @return java.lang.Object
     * @author yurj
     * @mail 1638234804@qq.com
     * @version 1.0
     * @date 2020/7/5 14:47
     */

    public static Object getThreadContext(String ctxKey) {
        Map ctxMap = (Map) userCtx.get();
        if (Objects.isNull(ctxMap)) {
            return null;
        }
        return ctxMap.get(ctxKey);
    }

    /**
     * 获取session上下文
     *
     * @param ctxKey
     * @return java.lang.Object
     * @author yurj
     * @mail 1638234804@qq.com
     * @version 1.0
     * @date 2020/7/5 14:55
     */

    public static Object getSessionContext(String ctxKey) {
        HttpSession session = (HttpSession) getThreadContext(GlobalNames.THREAD_CONTEXT_SESSION_KEY);
        if (Objects.nonNull(session)) {
            return session.getAttribute(ctxKey);
        }
        throw new AuthenticationException("Session is not in current thread context.");
    }

    /**
     * 设置线程上下文参数
     *
     * @param ctxKey
     * @param ctxValue
     * @return void
     * @author yurj
     * @mail 1638234804@qq.com
     * @version 1.0
     * @date 2020/7/5 14:47
     */

    public static void putThreadContext(String ctxKey, Object ctxValue) {
        Map ctxMap = (Map) userCtx.get();
        if (Objects.isNull(ctxMap)) {
            ctxMap = new HashMap(ApiConst.DEFAULT_INITIAL_CAPACITY);
            userCtx.set(ctxMap);
        }
        ctxMap.put(ctxKey, ctxValue);
    }

    /**
     * 删除线程上下文参数
     *
     * @param ctxKey
     * @return void
     * @author yurj
     * @mail 1638234804@qq.com
     * @version 1.0
     * @date 2020/7/5 14:48
     */

    public static void removeThreadContext(String ctxKey) {
        Map ctxMap = (Map) userCtx.get();
        if (Objects.nonNull(ctxMap)) {
            ctxMap.remove(ctxKey);
        }
    }

    /**
     * 初始化系统环境上下文
     *
     * @param request
     * @param response
     * @return void
     * @author yurj
     * @mail 1638234804@qq.com
     * @version 1.0
     * @date 2020/7/5 14:48
     */

    public static void initSystemEnvironmentContext(HttpServletRequest request, HttpServletResponse response) {
        initSystemEnvironmentContext(request, response, true);
    }

    /**
     * 初始化系统环境上下文
     *
     * @param request
     * @param response
     * @param session
     * @return void
     * @author yurj
     * @mail 1638234804@qq.com
     * @version 1.0
     * @date 2020/7/5 14:48
     */

    public static void initSystemEnvironmentContext(HttpServletRequest request, HttpServletResponse response, boolean session) {
        HttpSession httpSession = request.getSession(session);
        putThreadContext(GlobalNames.THREAD_CONTEXT_SESSION_KEY, httpSession);
        //当前用户从拦截器直接注入，无需从request获取，此处暂时无用
        if (httpSession != null) {
            putThreadContext(GlobalNames.SESSION_CONTEXT_USERINFO_KEY,
                    getSessionContext(Constants.SESSION_CURRENT_USER));
        } else {
            removeThreadContext(GlobalNames.SESSION_CONTEXT_USERINFO_KEY);
        }
        putThreadContext(GlobalNames.THREAD_CONTEXT_REQUEST_KEY, request);
        putThreadContext(GlobalNames.THREAD_CONTEXT_RESPONSE_KEY, response);
    }

    /**
     * 初始化用户信息
     *
     * @param userType
     * @param user
     * @return void
     * @author yurj
     * @mail 1638234804@qq.com
     * @version 1.0
     * @date 2020/7/5 14:32
     */

    public static void initCurrentUser(String userType, Object user, String token,String userId) {
        if (Objects.nonNull(userType) && Objects.nonNull(user)) {
            CurrentThreadUser currentUserInfo = CurrentThreadUser.builder()
                    .user(user)
                    .userType(userType)
                    .token(token)
                    .userId(userId)
                    .build();
            putThreadContext(GlobalNames.SESSION_CONTEXT_USERINFO_KEY,
                    currentUserInfo);
        } else {
            removeThreadContext(GlobalNames.SESSION_CONTEXT_USERINFO_KEY);
        }
    }

    /**
     * 设置缓存值
     *
     * @param key
     * @param value
     * @return void
     * @author yurj
     * @mail 1638234804@qq.com
     * @version 1.0
     * @date 2020/7/5 14:58
     */

    public static void putCache(String key, Object value) {
        if ((Objects.nonNull(key) && Objects.nonNull(value))) {
            cacheMap.put(key, value);
        }
    }

    /**
     * 获取缓存值
     *
     * @param key
     * @return java.lang.Object
     * @author yurj
     * @mail 1638234804@qq.com
     * @version 1.0
     * @date 2020/7/5 14:58
     */

    public static Object getCache(String key) {
        return cacheMap.get(key);
    }

    /**
     * 清除当前线程缓存值
     *
     * @param
     * @return void
     * @author yurj
     * @mail 1638234804@qq.com
     * @version 1.0
     * @date 2020/7/8 14:27
     */

    public static void clearThreadLocal() {
        userCtx.remove();
    }

}
